package laravel.mvc.model;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import entity_model.Entity;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty;
import laravel.Laravel;
import php.code.functions.Functions;

import static php.code.indentation.Indentation.DEFAULT;
import static php.code.Visibility.PUBLIC;
import static php.code.functions.TextLayout.INLINE;

public class BaseSubModel extends AbstractModel {

    private Property<Model> superModelProperty = new SimpleObjectProperty<>();

    public BaseSubModel(Laravel laravel, Entity entity) {
        super(laravel, entity.getTitle().getSingularized().prefix("Base"), entity);

        laravel.baseSubModels.put(entity, this);

        laravel.setOnFinished(() -> setSuperModel(laravel.models.get(entity.getTitle())));
    }

    private void setSuperModel(Model superModel) {
        this.superModelProperty.setValue(superModel);

        entityClass.doc("Base implementation for polymorphic sub-models of the '" + superModel.getName() + "' super-model");

        entityClass.createProperty(PUBLIC, "timestamps", false)
                .doc("Disabling Auto Timestamps");

        if (!entity.isAbstract())
            entityClass.createProperty(PUBLIC, "touches", Functions.array(INLINE, Lists.newArrayList(superModel.getTitle().toSnakeCase())))
                .doc("Update the parent's timestamps when the child model is updated");

        String methodName = superModel.getTitle().toLowerCamel();

        String returnStatement;
        try {
            returnStatement = String.format("return $this->morphOne('%s', '%s', null, 'id', 'id');",
                    superModel.getName(),
                    superModel.getMorphable().getName());
        }catch (Exception e){
            System.err.println(superModel.getName() + ": " + superModel.getEntityClass().getEntity().isAbstract());
            throw new RuntimeException(e);
        }

        entityClass.createMethod(PUBLIC, superModel.getTitle())
                .add(returnStatement)
                .doc("Polymorphic one-to-one relationship");

        entityClass.getFile().add(Joiner.on("\n").join(
                entityClass.getName() + "::deleted(function($child){",
                String.format("%s$%s = $child->%s();", DEFAULT, methodName, methodName),
                String.format("%s$%s->delete();", DEFAULT, methodName),
                "});"
        ));
    }

    public Model getSuperModel() {
        return superModelProperty.getValue();
    }

    public Property<Model> getSuperModelProperty() {
        return superModelProperty;
    }
}
